package com.defangit.award.orm;

import com.defangit.applicant.orm.TicketAddHandler;
import com.defangit.award.extend.point.OrmMappingEp;
import com.laogen.plugins.PluginManager;
import laogen.hibernate.RandomOrderBuilder;
import laogen.hibernate.SessionFactoryProvider;
import laogen.hibernate.util.config.AbstractConfig;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.internal.SessionFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HibernateUtil extends SessionFactoryProvider{

    public static Logger HIBERNATE_LOGGER= LoggerFactory.getLogger("org.hibernate.SQL");

    public static final HibernateUtil INSTANCE;

    static{
        INSTANCE=new HibernateUtil();
        SessionFactoryProvider.INSTANCE=INSTANCE;
    }
    private HibernateUtil(){

    }

    private StandardServiceRegistry fromConfig(AbstractConfig _config){
        return new StandardServiceRegistryBuilder()
                .applySetting("testWhileIdle","true")
                .applySetting("initialSize","3")
                .applySetting("minIdle","3")
                .applySetting("maxActive","30")
                .applySetting("driverClassName",_config.driverClass())
                .applySetting("url", _config.connectionUrl())
                .applySetting("username", _config.getUserName())
                .applySetting("password",_config.getPassword())
                .applySetting("hibernate.dialect",_config.dialect())
                .applySetting("hibernate.hbm2ddl.auto",_config.getHbm2ddl())
                /*todo 会影响性能
                .applySetting("hibernate.show_sql","false")
                .applySetting("hibernate.format_sql","true")
                .applySetting("hibernate.use_sql_comments","true")*/
                /**current session context class :(JTA & thread)控制currentSession处理机制*/
                .applySetting("hibernate.current_session_context_class","thread")
                .applySetting("hibernate.connection.provider_class","com.alibaba.druid.support.hibernate.DruidConnectionProvider")
                /*.applySetting("hibernate.c3p0.max_size", 810)
                .applySetting("hibernate.c3p0.min_size", 30)
                .applySetting("hibernate.c3p0.timeout",25000)
                .applySetting("hibernate.c3p0.acquire_increment",3)
                .applySetting("hibernate.c3p0.idle_test_period",300)*/
                .applySetting("hibernate.jdbc.batch_size",50)
                .applySetting("hibernate.jdbc.fetch_size",50)
                /*.applySetting("hibernate.c3p0.max_statements",100)
                .applySetting("hibernate.c3p0.maxStatementsPerConnection",100)
                .applySetting("hibernate.c3p0.debugUnreturnedConnectionStackTraces",true)
                .applySetting("hibernate.c3p0.unreturnedConnectionTimeout",240)
                .applySetting("hibernate.c3p0.acquireRetryAttempts",3)
                .applySetting("hibernate.c3p0.acquireRetryDelay",1000)
                .applySetting("hibernate.c3p0.numHelperThreads",10)*/
                //.applySetting("hibernate.c3p0.testConnectionOnCheckout",true)
                .applySetting("hibernate.connection.isolation",2)//事务隔离级别
                .applySetting("hibernate.connection.release_mode","on_close")
                .build();
    }
    public  void setDataSourceConfig(AbstractConfig _serverConfig) {
        serverConfig=_serverConfig;
        if(sessionFactory!=null) sessionFactory.close();
        sessionFactory=null;
    }

    private AbstractConfig serverConfig;
    private SessionFactory sessionFactory;
    public SessionFactory getSessionFactory() {
        if(sessionFactory==null||sessionFactory.isClosed()){
            StandardServiceRegistry registry=fromConfig(serverConfig);
            MetadataSources _src=new MetadataSources(registry)
                    .addResource("prize.hbm.xml")
                    .addResource("winningInfo.hbm.xml")
                    .addResource("award.hbm.xml")
                    .addResource("enroll.hbm.xml")
                    .addResource("ticket.hbm.xml")
                    .addResource("ticketType.hbm.xml");

            PluginManager.getInstance().getListeners(OrmMappingEp.class)
                    .parallelStream().forEach(mapping->{
                        mapping.extraMappings().parallelStream().forEach(_src::addInputStream);
            });

            if(this.serverConfig.dialect().contains("Derby")) {
                RandomOrderBuilder.setDefaultRandomOrder(RandomOrderBuilder.DerbyRandomOrder());
            }

            SessionFactoryBuilder builder = _src.buildMetadata().getSessionFactoryBuilder();

            sessionFactory =_src
                    .buildMetadata()
                    .getSessionFactoryBuilder()
                    .build();
            EventListenerRegistry evRegistry = ((SessionFactoryImpl) sessionFactory)
                    .getServiceRegistry()
                    .getService(EventListenerRegistry.class);
            evRegistry.getEventListenerGroup(EventType.POST_COMMIT_INSERT)
                    .appendListener(new PrizeUsedHandler());
//            evRegistry.getEventListenerGroup(EventType.POST_UPDATE)
//                    .appendListener(new PrizeUsedHandler());
            evRegistry.appendListeners(EventType.POST_COMMIT_UPDATE,new PrizeUsedHandler());
            evRegistry.appendListeners(EventType.POST_COMMIT_INSERT,new TicketAddHandler());
            //evRegistry.appendListeners(EventT);
//            evRegistry.getEventListenerGroup(EventType.POST_COMMIT_UPDATE)
//                    .appendListener(new PrizeUsedHandler());
        }
        return sessionFactory;
    }
}
